import java.util.ArrayList;
import java.util.Map.Entry;


public class LineChart {
	public float x,y,width,height;
	int maxYValue;
	int minX,maxX;
	public float plotHeight;

	// Highlight stuff
	Nationality highlightNationality;
	Continent highlightContinent;
	int xhl,yhl,xValhl;
	float valuehl;

	float  verticalMinValue=0;
	int verticalMinInterval=6/6,verticalMaxInterval=6/3;

	// Constructor of the linechart
	public LineChart(float x,float y,float width,float height,int minX,int maxX){
		this.x=x;
		this.y=y;
		this.width=width;
		this.height=height;
		this.maxYValue = 6;

		this.minX = minX;
		this.maxX = maxX;

		plotHeight = this.height-40;

	}

	// Draws all the linechart parts
	public void draw(){
		if(GLOBAL.map_nPerHourPerNationality.size()==0)return; 
		float maxValue = 0;

		drawVerticalLabels(0, maxYValue, verticalMinInterval, verticalMaxInterval, "");
		drawUnits("# / hh");
		drawXlabels();

		GLOBAL.COLORS.reset();
		GLOBAL.processing.strokeWeight(1);
		GLOBAL.processing.stroke(140,200);
		highlightNationality = null;
		highlightContinent = null;
		
		if(!GLOBAL.continents_colors)
			maxValue = drawNationalities();
		else
			maxValue = drawContinents();

		drawHighLight();
		checkMaxYVal(maxValue);
	}



	// Draw the chart lines and colors if the continents have to be displayed
	private float drawContinents() {
		float maxValue=0;
		float[] values = new float[24];
		float value = 0;
		// Initialization
		for (int i=0; i< values.length; i++)
			values[i] = 0;
		boolean first = true;
		
		
		for (Entry<Continent,ArrayList<Float>> entry : GLOBAL.map_nPerHourPerContinent.entrySet()) {

			// Values of this continent
			ArrayList<Float> valuePerHour = entry.getValue();	

			if (GLOBAL.map_usersPerContinent.get(entry.getKey()) == 0) continue;

			if(first){
				// First area 

				GLOBAL.processing.beginShape();
				GLOBAL.processing.fill(entry.getKey().color);
				for (int j=0;j< valuePerHour.size();j++) {

					float yVal=(float) valuePerHour.get(j)/GLOBAL.map_usersPerContinent.get(entry.getKey());
					if(maxValue<yVal)maxValue = yVal;
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);

					// Highlight
					int yLastV = (int) GLOBAL.processing.map(values[j], 0, maxYValue, y+plotHeight, y); 
					if(Math.abs(GLOBAL.processing.mouseX - xV) < 11 && GLOBAL.processing.mouseY>yV && GLOBAL.processing.mouseY<=yLastV
							&& highlightContinent==null)
					{
						xhl = GLOBAL.processing.mouseX;
						yhl = GLOBAL.processing.mouseY;
						highlightContinent = entry.getKey();
						valuehl = (float)valuePerHour.get(j)/GLOBAL.map_usersPerContinent.get(entry.getKey());
						xValhl = j;
					}


				}
				GLOBAL.processing.vertex(x+width, y+plotHeight);
				GLOBAL.processing.vertex(x,y+plotHeight);
				GLOBAL.processing.endShape(GLOBAL.processing.CLOSE);

			}
			else{
				// Other areas

				GLOBAL.processing.beginShape();
				GLOBAL.processing.fill(entry.getKey().color);
				for (int j=valuePerHour.size()-1;j>=0;j--) {
					float yVal=(float)valuePerHour.get(j)/GLOBAL.map_usersPerContinent.get(entry.getKey())+values[j];
					if(maxValue<yVal)maxValue = yVal;
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);

					// Highlight
					int yLastV = (int) GLOBAL.processing.map(values[j], 0, maxYValue, y+plotHeight, y); 
					if(Math.abs(GLOBAL.processing.mouseX - xV) < 11 && GLOBAL.processing.mouseY>yV && GLOBAL.processing.mouseY<=yLastV 
							&& highlightContinent==null)
					{
						xhl = GLOBAL.processing.mouseX;
						yhl = GLOBAL.processing.mouseY;
						highlightContinent = entry.getKey();
						valuehl = (float)valuePerHour.get(j)/GLOBAL.map_usersPerContinent.get(entry.getKey());
						xValhl = j;
					}

				}
				for (int j=0;j< valuePerHour.size();j++) {
					float yVal=values[j];
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);
				}
				GLOBAL.processing.endShape(GLOBAL.processing.CLOSE);


			}



			// Update hours counts
			for (int i=0; i<valuePerHour.size(); i++)
				if(valuePerHour.get(i) > 0)
					values[i] = values[i] + (float)valuePerHour.get(i)/GLOBAL.map_usersPerContinent.get(entry.getKey());

			first = false;
		}	
		
		
		return maxValue;
	}

	
	// Draw the chart lines and colors if the nationalities have to be displayed
	private float drawNationalities() {
		float maxValue=0;
		float[] values = new float[24];
		float value = 0;
		// Initialization
		for (int i=0; i< values.length; i++)
			values[i] = 0;
		boolean first = true;



		for (Entry<Nationality,ArrayList<Float>> entry : GLOBAL.map_nPerHourPerNationality.entrySet()) {

			// Values of this nationality
			ArrayList<Float> valuePerHour = entry.getValue();	

			if (GLOBAL.map_usersPerNationality.get(entry.getKey()) == 0) continue;

			if(first){
				// First area 

				GLOBAL.processing.beginShape();
				GLOBAL.processing.fill(entry.getKey().color);
				for (int j=0;j< valuePerHour.size();j++) {

					float yVal= (float)valuePerHour.get(j)/GLOBAL.map_usersPerNationality.get(entry.getKey());
					if(maxValue<yVal)maxValue = yVal;
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);

					// Highlight
					int yLastV = (int) GLOBAL.processing.map(values[j], 0, maxYValue, y+plotHeight, y); 
					if(Math.abs(GLOBAL.processing.mouseX - xV) < 11 && GLOBAL.processing.mouseY>yV && GLOBAL.processing.mouseY<=yLastV
							&& highlightNationality==null)
					{
						xhl = GLOBAL.processing.mouseX;
						yhl = GLOBAL.processing.mouseY;
						highlightNationality = entry.getKey();
						valuehl = (float)valuePerHour.get(j)/GLOBAL.map_usersPerNationality.get(entry.getKey());
						xValhl = j;
					}


				}
				GLOBAL.processing.vertex(x+width, y+plotHeight);
				GLOBAL.processing.vertex(x,y+plotHeight);
				GLOBAL.processing.endShape(GLOBAL.processing.CLOSE);

			}
			else{
				// Other areas

				GLOBAL.processing.beginShape();
				GLOBAL.processing.fill(entry.getKey().color);
				for (int j=valuePerHour.size()-1;j>=0;j--) {
					float yVal=(float)valuePerHour.get(j)/GLOBAL.map_usersPerNationality.get(entry.getKey())+values[j];
					if(maxValue<yVal)maxValue = yVal;
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);

					// Highlight
					int yLastV = (int) GLOBAL.processing.map(values[j], 0, maxYValue, y+plotHeight, y); 
					if(Math.abs(GLOBAL.processing.mouseX - xV) < 11 && GLOBAL.processing.mouseY>yV && GLOBAL.processing.mouseY<=yLastV 
							&& highlightNationality==null)
					{
						xhl = GLOBAL.processing.mouseX;
						yhl = GLOBAL.processing.mouseY;
						highlightNationality = entry.getKey();
						valuehl = (float)valuePerHour.get(j)/GLOBAL.map_usersPerNationality.get(entry.getKey());
						xValhl = j;
					}

				}
				for (int j=0;j< valuePerHour.size();j++) {
					float yVal=values[j];
					float xVal= j;
					int xV = (int) GLOBAL.processing.map(xVal, minX,maxX,x,x+width);
					int yV = (int) GLOBAL.processing.map(yVal, 0, maxYValue, y+plotHeight, y); 
					GLOBAL.processing.vertex(xV, yV);
				}
				GLOBAL.processing.endShape(GLOBAL.processing.CLOSE);


			}



			// Update hours counts
			for (int i=0; i<valuePerHour.size(); i++)
				if(valuePerHour.get(i) > 0)
					values[i] = values[i] + (float)valuePerHour.get(i)/GLOBAL.map_usersPerNationality.get(entry.getKey());

			first = false;
		}	
		
		
		
		return maxValue;
	}

	
	// Checks and if necessary updates the maximum y value of the chart
	private void checkMaxYVal(float maxValue) {

		int threshold = maxYValue/10;

		if(maxValue > maxYValue - maxYValue/10){
			maxYValue = maxYValue + 6;
			verticalMaxInterval = maxYValue/3;
			verticalMinInterval = maxYValue/6;
		}
	}

	// Draw the highlight of the chart
	public void drawHighLight(){
		if(highlightNationality == null && highlightContinent == null) return;
		if(highlightNationality != null){
		GLOBAL.processing.fill(GLOBAL.colorBackground); 
		GLOBAL.processing.rectMode(GLOBAL.processing.CORNER); 
		GLOBAL.processing.noStroke();
		GLOBAL.processing.textFont(GLOBAL.plotFont, 12);
		float max = GLOBAL.processing.max(GLOBAL.processing.textWidth("# of plays pp: "+GLOBAL.processing.nfc(valuehl, 1)),
				GLOBAL.processing.textWidth(highlightNationality.getName()+"        "+"h: "+(int)(xValhl)));
		GLOBAL.processing.rect(xhl+10, yhl, max+15,15*2);
		GLOBAL.processing.fill(GLOBAL.textColor);
		GLOBAL.processing.textAlign(GLOBAL.processing.LEFT);
		//GLOBAL.processing.text(highlight.getName()+": "+(int)(valuehl),xhl+12,yhl+11);
		GLOBAL.processing.text(highlightNationality.getName()+"        "+"hh: "+(int)(xValhl),xhl+12,yhl+11);
		GLOBAL.processing.text("# of plays pp: "+GLOBAL.processing.nfc(valuehl, 1),xhl+12,yhl+26);
		}
		else if(highlightContinent!=null){
			GLOBAL.processing.fill(GLOBAL.colorBackground); 
			GLOBAL.processing.rectMode(GLOBAL.processing.CORNER); 
			GLOBAL.processing.noStroke();
			GLOBAL.processing.textFont(GLOBAL.plotFont, 12);
			float max = GLOBAL.processing.max(GLOBAL.processing.textWidth("# of plays pp: "+GLOBAL.processing.nfc(valuehl, 1)),
					GLOBAL.processing.textWidth(highlightContinent.fullName+"        "+"h: "+(int)(xValhl)));
			GLOBAL.processing.rect(xhl+10, yhl, max+15,15*2);
			GLOBAL.processing.fill(GLOBAL.textColor);
			GLOBAL.processing.textAlign(GLOBAL.processing.LEFT);
			//GLOBAL.processing.text(highlight.getName()+": "+(int)(valuehl),xhl+12,yhl+11);
			GLOBAL.processing.text(highlightContinent.fullName+"        "+"hh: "+(int)(xValhl),xhl+12,yhl+11);
			GLOBAL.processing.text("# of plays pp: "+GLOBAL.processing.nfc(valuehl, 1),xhl+12,yhl+26);
		}

	}

	// Draw x labels of the chart
	public void drawXlabels(){
		int cy = 0;

		for(int i=0;i<24;i++){
			int xV = (int) GLOBAL.processing.map(i, minX,maxX,x,x+width);

			// Draw the volume name
			GLOBAL.processing.fill(GLOBAL.textColor);
			GLOBAL.processing.textFont(GLOBAL.plotFont,10);
			GLOBAL.processing.textAlign(GLOBAL.processing.CENTER);
			GLOBAL.processing.text(i, xV , cy + y + plotHeight + 15);
		}
	}


	// Draw units of the chart
	public void drawUnits(String u) {
		// Text
		GLOBAL.processing.fill(GLOBAL.textColor);
		GLOBAL.processing.textFont(GLOBAL.plotFont,9);
		GLOBAL.processing.textAlign(GLOBAL.processing.CENTER);
		GLOBAL.processing.text(u, x - 13, y + plotHeight + 23);
	}



	// Draw vertical labels of the chart
	public void drawVerticalLabels(float minValue, float maxValue, int minInterval, int maxInterval, String s){
		GLOBAL.processing.fill(GLOBAL.textColor);
		GLOBAL.processing.textFont(GLOBAL.plotFont,10);
		GLOBAL.processing.stroke(GLOBAL.colorLines);
		GLOBAL.processing.strokeWeight(1);

		float min = minValue;
		float max = maxValue;

		int yIntervalMinor = minInterval;
		int yIntervalMayor = maxInterval;

		float plotX1 = x;
		float plotX2 = x + width;

		for (float v = min; v <= max; v += yIntervalMinor) {

			if (v % yIntervalMinor == 0) {     // If a tick mark
				float y = GLOBAL.processing.map(v, min, max, this.y + plotHeight, this.y);  
				if (v % yIntervalMayor == 0) {        // If a major tick mark
					float textOffset = GLOBAL.processing.textAscent()/3;  // Center vertically
					if (v == min) {
						textOffset = 0;                   // Align by the bottom
					} 
					else if (v == max) {
						textOffset = GLOBAL.processing.textAscent() - 4;        // Align by the top
					}
					GLOBAL.processing.textAlign(GLOBAL.processing.RIGHT);
					GLOBAL.processing.text(GLOBAL.processing.floor(v) + s, plotX1 - 8, y + textOffset);
					if (v % maxInterval == 0) {
						GLOBAL.processing.line(plotX1 - 4, y, plotX2, y);
					}
					else {
						GLOBAL.processing.line(plotX1 - 4, y, plotX1, y);     // Draw major tick
					}
				} 
				else {
					GLOBAL.processing.line(plotX1 - 2, y, plotX1, y);   // Draw minor tick
				}
			}
		}

		GLOBAL.processing.noStroke();


	}


}
